package ca.cbc.medialib.service;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import ca.cbc.medialib.Bootstrap;
import ca.cbc.medialib.entity.Category;
import ca.cbc.medialib.entity.Media;
import ca.cbc.medialib.entity.MediaFile;
import ca.cbc.medialib.entity.Release;
import ca.cbc.medialib.exception.ThePlatformObjectNotFoundException;
import com.theplatform.media.api.data.objects.Chapter;
import org.slf4j.Logger;
import com.google.common.base.Function;
import com.theplatform.data.api.DataObjectField;
import com.theplatform.data.api.exception.ObjectNotFoundException;
import com.theplatform.data.api.objects.FieldInfo;
import com.theplatform.data.api.objects.type.CategoryInfo;
import com.theplatform.media.api.fields.MediaField;

/**
 * =============================================
 * Copyright (c) 2011 Canadian Broadcasting Corporation.
 * All rights reserved.
 * <p/>
 * ca.cbc.medialib.service.MediaService.java
 * =============================================
 * <p/>
 * PURPOSE:	Manages communicate with thePlatform for Media
 * <p/>
 * =============================================
 * MODIFICATION		LOG	DATE		REASON / Change Request #
 * Liu Yang			Jun 22, 2011	Initial file creation
 * =============================================
 */

public final class MediaService extends EntityService {
    private static Logger logger = org.slf4j.LoggerFactory.getLogger(MediaService.class);
    private ReleaseService rs = new ReleaseService();
    private CategoryService cs = new CategoryService();
    private MediaFileService mfs = new MediaFileService();

    private static String[] mediaFieldParams = new String[]{
            DataObjectField.id.toString(),
            DataObjectField.title.toString(),
            DataObjectField.description.toString(),
            MediaField.pubDate.toString(),

            MediaField.keywords.toString(),
            MediaField.thumbnails.toString(),
            MediaField.availableDate.toString(),
            MediaField.content.toString(), //to get media length
            MediaField.categories.toString(),
            MediaField.defaultThumbnailUrl.toString(),
            DataObjectField.customValues.toString(),
            MediaField.expirationDate.toString(),
            MediaField.excludeCountries.toString(),
            MediaField.countries.toString(),
            MediaField.chapters.toString(),
            MediaField.approved.toString()
    };

    private Function<com.theplatform.media.api.data.objects.Media, Media> convertMedia = new Function<com.theplatform.media.api.data.objects.Media, Media>() {
        @Override
        public Media apply(com.theplatform.media.api.data.objects.Media media) {
            //get custom fields
            Map<String, Object> mediaInfoMap = new HashMap<String, Object>();

            if (media.getCustomValues() != null)
                for (FieldInfo field : media.getCustomValues().keySet()) {

                    Object value = media.getCustomValues().get(field);
                    String fieldName = field.getFieldName();
                    mediaInfoMap.put(fieldName, value);
                }


            /*
            * if expiration date is null, set to one month expire
            *
            */
            Date exprationDate = media.getExpirationDate();
//            if (exprationDate == null) {
//                Calendar cal = Calendar.getInstance();
//                cal.add(Calendar.MONTH, 1);
//                exprationDate = cal.getTime();
//            }

            /*
            * build counties here
            */
            StringBuilder sb = new StringBuilder();
            String[] countries = media.getCountries();
            if (countries != null && countries.length > 0) {
                sb.append(countries[0]);
                for (int i = 1; i < countries.length; i++)
                    sb.append(" ").append(countries[i]);
            }
            Chapter[] chapters = media.getChapters();
            StringBuilder chapterString = new StringBuilder();
            if (chapters !=null){
                for ( Chapter chapter : chapters){
                    chapterString.append(getDurationAsString(chapter.getStartTime())).append(',') ;
                }
            }else {
                logger.debug("Chapters property is null");
            }

            Media cbcMedia = new Media.Builder().withId(zeroOrLong(removePrefix(nullOrString(media.getId()))))
                    .withTitle((nullOrString(media.getTitle())))
                    .withDescription((nullOrString(media.getDescription())))
                    .withAirDate(media.getPubDate())
                    .withGenre((nullOrString(mediaInfoMap.get("genre"))))
                    .withKeywords((nullOrString(media.getKeywords())))
                    .withThumbnailUrl((nullOrString(media.getDefaultThumbnailUrl())))
                    .withAvailableDate(media.getAvailableDate())
                    .withMobileExpiryDate(exprationDate)
                    .withSeasonNumber((nullOrString(mediaInfoMap.get("seasonNumber"))))
                    .withEpisodeNumber((nullOrString(mediaInfoMap.get("episodeNumber"))))
                    .withAdCategory((nullOrString(mediaInfoMap.get("adCategory"))))
                    .withAudioVideo((nullOrString(mediaInfoMap.get("audioVideo"))))
                    .withLiveOndemand((nullOrString(mediaInfoMap.get("liveOndemand"))))
                    .withAvailableInMobile((nullOrString(mediaInfoMap.get("availableInMobile"))))
                    .withShow((nullOrString(mediaInfoMap.get("show"))))
                    .withChapterStartTimes(nullOrString(chapterString.toString()))
                    .withAccount((nullOrString(mediaInfoMap.get("contentArea"))))
                    .withExcludeCountries(media.getExcludeCountries())
                    .withCountries(nullOrString(sb))
                    .withStreamingCategoryFullTitle(null) //will assign later
                    .withSubtitle(nullOrString(mediaInfoMap.get("subtitles")))
                    .withAdRules(nullOrString(mediaInfoMap.get("adRules")))
                    .withUnapprovedDate(mediaInfoMap.get("unapprovedDate") == null ? null : (Date)mediaInfoMap.get("unapprovedDate"))
                    .withApproved(media.getApproved())
                    .buildNew();


            /*
            * Assign category here
            * For some reason, media.getCategoryIds() don't work
            */
            if (media.getCategories() != null) {
                for (CategoryInfo ci : media.getCategories())
                    try {
                        cbcMedia.addCategory(cs.findByFullTitle(ci.getName()));
                    } catch (ThePlatformObjectNotFoundException e) {
                        logger.warn("Category object not found with media {}", media.getId().toString());
                    }

                if (cbcMedia.getCategories().size() > 0) {
                    Category c = cbcMedia.getCategories().get(0);
                    if (c != null)
                        cbcMedia.setStreamingCategoryFullTitle(c.getFullTitle());
                }
            }


            return cbcMedia;
        }
    };

    public Media getMediaWithReleaseId(long releaseId) throws ThePlatformObjectNotFoundException {
        Release release = rs.get(releaseId);
        MediaFile mf = mfs.get(release.getMediaFileId());
        Media media = get(release.getMediaId());
        media.setReleaseId(releaseId);
        media.setDelivery(release.getDelivery());
        media.setMobileId(release.getYospaceId());
        media.setReleaseUrl(release.getReleaseUrl());
        media.setLength(mf.getLength());
        media.setOriginalFileName(mf.getFileName());
        return media;
    }

    public void saveYospaceId(long releaseId, long yospaceId) throws ThePlatformObjectNotFoundException {
        rs.saveYospaceId(releaseId, yospaceId);
    }

    /*
    * Set yospaceId to 0 and set avaiableInMobile to false
    */
    public void deleteYospaceId(long releaseId, long mediaId) throws ThePlatformObjectNotFoundException {
        rs.deleteYospaceId(releaseId, mediaId);
    }

    /*
    * This method will return incomplete media, use getWithReleaseId instead
    */
    public Media get(long id) throws ThePlatformObjectNotFoundException {
        try {
            com.theplatform.media.api.data.objects.Media media = Bootstrap.instance.getMediaClient().get(
                    new URI(String.valueOf(id)),
                    mediaFieldParams
            );
            return convertMedia.apply(media);
        } catch (URISyntaxException e) {
            throw new ThePlatformObjectNotFoundException("Media URI Syntex Error", e);
        } catch (ObjectNotFoundException e) {
            throw new ThePlatformObjectNotFoundException("Media object not found", e);
        }
    }
}
